<?php if(!defined('BASEPATH')) exit('No direct access to this file allowed');


/******************************************************************************\
 *  IgnitionBase Manifesto
 *  
 *  Origin
 *
 *  IgnitionBase started out as an exercise in building a HMVC framework to
 *  encourage the usage of proper architectural patterns in building web-based
 *  applications. It is meant to be a good example of lean and modular
 *  development and is originally meant to accomplish three goals - (1) to
 *  provide a good base for learning proper web-application development with
 *  the proper patterns and conventions, (2) to provide a rapid and highly
 *  flexible base framework for developing complex applications, and (3) to
 *  enforce and encourage Object-Oriented PHP development.
 *
 *  Change Log
 *  0.1     -   Initial version of IgnitionBase
 *
 *  Standard Tags:
 *  @author     Ruben Tan
 *  @copyright  Copyright (c) 2008 Rendervault
 *
 *  Developer Tags:
 *  @package    system
\******************************************************************************/
final class IgnitionBase
{
    protected static $_instance = null;
    
    // Constants for loader
    const SUBSYSTEM     = 'subsystems';
    const COMPONENT     = 'components';
    const MODULE        = 'modules';
    
    protected $_paths = array();
    
    /**--------------------------------------------------------------------------------------
     *  IgnitionBase constructor
     *
     *  @author     name
     *  
     *  @access     protected
     *  @param      type        description
     *  @return     type        description
     */
    private function __construct( )
    { 
        $this->_paths = array(
                            'subsystems' => 'system::subsystems::',
                            'components' => 'system::components::',
                            'modules' => 'modules::'
                        );
    }
    
    /**--------------------------------------------------------------------------------------
     *  IgnitionBase clone constructor
     *
     *  @author     Ruben Tan
     *  
     *  @access     private
     *  @param      void
     *  @return     void
     */ 
    private function __clone( )
    { }
    
    /**--------------------------------------------------------------------------------------
     *  IgnitionBase clone destructor
     *
     *  @author     Ruben Tan
     *  
     *  @access     public
     *  @param      void
     *  @return     void
     */ 
    public function __destruct( )
    { }
    
    /**--------------------------------------------------------------------------------------
     *  Returns a singleton instance
     *
     *  @author     Ruben Tan
     *
     *  @access     public
     *  @param      void
     *  @return     instance    A reference to the static IgnitionBase instance
     */
    public static function get_instance( ) 
    {
        if( !isset( IgnitionBase::$_instance ) )
        {
            IgnitionBase::$_instance = new IgnitionBase( );
        }
        
        return IgnitionBase::$_instance;
    }
    
    /**--------------------------------------------------------------------------------------
     *  Retrieves the path of a system object
     *
     *  @author     Ruben Tan
     *
     *  @access     public
     *  @param      string      The system object's type ID
     *  @return     string      The system object's path
     */
    public function get_path( $path_type )
    {
        if( isset( $this->_paths[$path_type] ) )
        {
            return $this->_paths[$path_type];
        }
        
        return '';
    }
    
    /**--------------------------------------------------------------------------------------
     *  Sets the path of a system object
     *
     *  @author     Ruben Tan
     *
     *  @access     public
     *  @param      string      The system object's type ID
     *  @param      string      The new path name
     *  @return     void
     */
    public function set_path( $path_type, $new_path )
    {
        if( isset( $this->_paths[$path_type] ) )
        {
            $this->_paths[$path_type] = $new_path;
        }
    }
    
    /**--------------------------------------------------------------------------------------
     *  Main process
     *
     *  @author     Ruben Tan
     *
     *  @access     public
     *  @param      array       an array of subsystems to be loaded
     *  @return     void
     */
    public function process( $subsystems )
    {   
        // Loads all subsystems
        foreach( $subsystems as $alias => $classpath )
        {
            $this->load( IgnitionBase::SUBSYSTEM, $classpath, $alias );
        }
        
        // System sanitary check
        $status = TRUE;
        //$status = $this->_check_integrity( );
        if( !$status )
        {
            //$this->error->integrity( $status );
        }
        else
        {
            // Route user's request
            $this->router->hook(' pre-process-request' );
            $this->router->run( );        
            $this->router->hook( 'post-process-request' );
            
            // Renders output to screen
            $this->router->hook( 'pre-flush-render' );
            //$this->render->flush( );
        }
    }
    
    /**--------------------------------------------------------------------------------------
     *  Load various resources and return an instance of the loaded entity
     *
     *  @author     Ruben Tan
     *
     *  @access     public
     *  @param      int         The type of resource to load
     *  @param      string      The full path of the resource
     *  @param      alias       The alias to refer it by
     *  @return     object      An instance of the object
     */
    public function load( $type, $class_path, $alias = '' )
    {
        $object = FALSE;        
        $prefix_path = $this->get_path( $type );
        
        // Begin loading
        $class_arr = explode( NS, $class_path );
        $class_name = ucfirst( strtolower( end( $class_arr ) ) );
        $real_path = BASEPATH . str_replace( NS, DS, $prefix_path . $class_path ) . EXT;
          
        // Flag the pre load component hook (only for subsystems and components)
        if( isset( $this->router ) && $alias !== '' ) 
        {
            if( $type == IgnitionBase::SUBSYSTEM )
            {
                $this->router->hook( 'pre-load-' . $alias );
            }
        }
        
        // Stop loading if the file does not exist
        if( !file_exists( $real_path ) ) 
        {
            throw new Exception('File does not exist: ' . $real_path );
        }
        
        @ob_start();
        
        // Include the file
        include_once( $real_path );
        
        if( !class_exists($class_name) ) 
        {
            throw new Exception('The class: ' . $class_name . ' does not exist in file: ' . $real_path );
        }
        
        // If it is a subsystem object, attach it to the core
        if( $type == IgnitionBase::SUBSYSTEM )
        { 
            // Make sure there's an alias. If not, use the class name instead
            if( $alias == '' )
            {
                $alias = strtolower($class_name);
            }
            
            // Release the previous subsystem if it has already been loaded
            if( isset($this->$alias) ) 
            {
                unset($this->$alias);
            }
            
            $this->$alias = new $class_name( $this );
            $object = $this->$alias;
        }
        else
        {
            $object = new $class_name( );
        }
        
        @ob_end_clean();
        
        // Flag the post load component hook (only for subsystems and components)
        if( isset( $this->router ) && $alias !== '' ) 
        {
            if( $type == IgnitionBase::SUBSYSTEM )
            {
                $this->router->hook( 'pre-load-' . $alias );
            }
        }
        
        // Mark this point in the profiler
        if( isset( $this->profiler ) ) 
        {
            $this->profiler->mark('loaded ' . $class_name );
        }
        
        // Don't return a bad object
        if( $object === FALSE ) 
        {
            throw new Exception('Failed to load ' . $type);
        }
        
        return $object;
    }
}